/**
 * Description: Super class of TriggerHandler
 * Author: peter chen
 * Company: DCIT
 * Date: 2017/11/25
**/
public abstract with sharing class CMN_TriggerHandler {
    public static final String OPERATION_BEFORE_INSERT = 'beforeinsert';
    public static final String OPERATION_AFTER_INSERT = 'afterinsert';
    public static final String OPERATION_BEFORE_UPDATE = 'beforeupdate';
    public static final String OPERATION_AFTER_UPDATE = 'afterupdate';
    public static final String OPERATION_BEFORE_DELETE = 'beforedelete';
    public static final String OPERATION_AFTER_DELETE = 'afterdelete';

    /**
     * trigger name set 
     */
    public static Set<String> recursiveTriggerSet = new Set<String>();

    /**
     * trigger Name & operation set
     */
    public static Set<String> operationRecursiveTriggerSet = new Set<String>();


    public Boolean isTriggerSkip(){
        return false;
    }

    public void setIsRecursive(){
        recursiveTriggerSet.add(getTriggerName());
    }

    public Boolean isRecursive(){
        return recursiveTriggerSet.contains(getTriggerName());
    }

    public void setOperationRecursive(String operation){
        operationRecursiveTriggerSet.add(getTriggerName() + operation);
    }


    public Boolean isOperationRecursive(String operation){
        return operationRecursiveTriggerSet.contains(getTriggerName() + operation);
    }

    public void execute() {
        try {
            if (isTriggerSkip()) {
                return;
            }
            if (Trigger.isBefore && Trigger.isInsert) {
                onBeforeInsert(Trigger.new);
                setOperationRecursive(OPERATION_BEFORE_INSERT);
            } else if (Trigger.isBefore && Trigger.isUpdate) {
                onBeforeUpdate(Trigger.old, Trigger.oldMap, Trigger.new, Trigger.newMap);
                setOperationRecursive(OPERATION_BEFORE_UPDATE);
            } else if (Trigger.isBefore && Trigger.isDelete) {
                onBeforeDelete(Trigger.old, Trigger.oldMap);
                setOperationRecursive(OPERATION_BEFORE_DELETE);
            } else if (Trigger.isAfter && Trigger.isInsert) {
                onAfterInsert(Trigger.new, Trigger.newMap);
                setOperationRecursive(OPERATION_AFTER_INSERT);
            } else if (Trigger.isAfter && Trigger.isUpdate) {
                onAfterUpdate(Trigger.old, Trigger.oldMap, Trigger.new, Trigger.newMap);
                setOperationRecursive(OPERATION_AFTER_UPDATE);
            } else if (Trigger.isAfter && Trigger.isDelete) {
                onAfterDelete(Trigger.old, Trigger.oldMap);
                setOperationRecursive(OPERATION_AFTER_DELETE);
            }
        } finally {
            setIsRecursive();
        }
    }


    public abstract String getTriggerName();

    public abstract void onBeforeInsert(List<SObject> newList);

    public abstract void onBeforeUpdate(List<SObject> oldList, Map<Id, SObject> oldMap, List<SObject> newList, Map<Id, SObject> newMap);

    public abstract void onBeforeDelete(List<SObject> oldList, Map<Id, SObject> oldMap);

    public abstract void onAfterInsert(List<SObject> newList, Map<Id, SObject> newMap);

    public abstract void onAfterUpdate(List<SObject> oldList, Map<Id, SObject> oldMap, List<SObject> newList, Map<Id, SObject> newMap);

    public abstract void onAfterDelete(List<SObject> oldList, Map<Id, SObject> oldMap);
}